home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / give < prev    next >
Encoding:
Text File  |  1989-02-03  |  13.5 KB  |  605 lines

  1. Path: xanth!mcnc!rutgers!tut.cis.ohio-state.edu!cwjcc!hal!ncoast!allbery
  2. From: daveb@geac.UUCP (David Collier-Brown)
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i018: Give -- a "secure" cat program
  5. Message-ID: <3143@geac.UUCP>
  6. Date: 8 Aug 88 12:22:04 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: daveb@geac.UUCP (David Collier-Brown)
  9. Organization: GEAC Computers, Toronto, CANADA
  10. Lines: 592
  11. Approved: allbery@ncoast.UUCP
  12.  
  13. Posting-number: Volume 4, Issue 18
  14. Submitted-by: "David Collier-Brown" <daveb@geac.UUCP>
  15. Archive-name: give
  16.  
  17. Give is a program to give copies of files to ONLY persons on a
  18. list.  It used to be available on some v6/PWB sites where competing
  19. groups were playing dirty tricks on each other.  It may be of some
  20. use in a student or paranoid commercial environment.
  21.  
  22. #! /bin/sh
  23. # This is a shell archive.  Remove anything before this line, then unpack
  24. # it by saving it into a file and typing "sh file".  To overwrite existing
  25. # files, type "sh file -c".  You can also feed this as standard input via
  26. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  27. # will see the following message at the end:
  28. #        "End of shell archive."
  29. # Contents:  README give.c Makefile give.1
  30. # Wrapped by daveb@geac on Wed Jul 20 14:15:35 1988
  31. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  32. if test -f README -a "${1}" != "-c" ; then 
  33.   echo shar: Will not over-write existing file \"README\"
  34. else
  35. echo shar: Extracting \"README\" \(268 characters\)
  36. sed "s/^X//" >README <<'END_OF_README'
  37. X    This is a reproduction of a v6 utility, for people who wish to
  38. Xlive in a paranoid universe.
  39. X
  40. X    It was written in the V7/Sys V style on a Berkeley 4.2 Vax (DEC
  41. XULTRIX), and is expected to be portable to any Unix machine with a
  42. Xdatabase utility resembling dbx(3).
  43. END_OF_README
  44. if test 268 -ne `wc -c <README`; then
  45.     echo shar: \"README\" unpacked with wrong size!
  46. fi
  47. # end of overwriting check
  48. fi
  49. if test -f give.c -a "${1}" != "-c" ; then 
  50.   echo shar: Will not over-write existing file \"give.c\"
  51. else
  52. echo shar: Extracting \"give.c\" \(7990 characters\)
  53. sed "s/^X//" >give.c <<'END_OF_give.c'
  54. X/*
  55. X * give -- a paranoid's cat program
  56. X */
  57. X#include <stdio.h>
  58. X#include <pwd.h>
  59. X#include <fcntl.h>
  60. X#include <sys/param.h>
  61. X#include <sys/types.h>
  62. X#include <sys/stat.h>
  63. X
  64. X#ifdef DEBUG
  65. X#define INSTANTIATE"
  66. X#endif
  67. X#include "debug.h"
  68. X
  69. X#define PR (void) fprintf(stderr,
  70. X#define EQ(a,b) strcmp(a,b) == 0
  71. X#define ERR (-1)
  72. X#define EOS '\0'
  73. X#define YES 1    /* Function returns. */
  74. X#define NO 0
  75. X#define OK 0    /* Program exit codes */
  76. X#define BAD 1
  77. X#define AWFULL 3
  78. X
  79. Xtypedef struct {
  80. X    char    *dptr;
  81. X    int    dsize;
  82. X} DATUM;
  83. X
  84. Xchar *ProgName = NULL;
  85. Xusage() {
  86. X    PR "Usage: %s [person] file...\n",ProgName);
  87. X}
  88. X
  89. Xmain(argc,argv) int argc; char *argv[]; {
  90. X    void give(), take(), remove(), exit();
  91. X
  92. X    begin("main");
  93. X    ProgName = argv[0];
  94. X    if (argc < 2) {
  95. X        if (exists(".give.dir")) {
  96. X            /* Say what we've got. */
  97. X            printDB();
  98. X        }
  99. X        else {
  100. X            /* Tell the user the usage. */
  101. X            usage();
  102. X            exit(BAD);
  103. X        }
  104. X    }
  105. X    else if (argv[1][0] == '-') {
  106. X        switch (toupper(argv[1][1])) {
  107. X        case 'D': /* Its the owner doing cleanup. */
  108. X            remove(argc-2,(char **)&argv[2]);
  109. X            break;
  110. X        case 'T': /* Force it to "take". */
  111. X            take(argc-2,(char **)&argv[2]);
  112. X            break;
  113. X        default: /* Error in usage. */
  114. X            usage();
  115. X            exit(BAD);    
  116. X        }
  117. X    }
  118. X    else if (ownerIsRunningMe()) {
  119. X        /* Its a give-to-someone (nonsetuid) request. */
  120. X        give(argc-1,(char **)&argv[1]);
  121. X    }
  122. X    else {
  123. X        /* Its a setuid-owner cat request. */
  124. X        take(argc-1,(char **)&argv[1]);
  125. X
  126. X    }
  127. X    end();
  128. X    exit(OK);
  129. X}
  130. X
  131. X/*
  132. X * take -- cat the file, if both it and the user match up
  133. X */
  134. X void
  135. Xtake(count, arg) int count; char *arg[]; {
  136. X    int    i;
  137. X    char    *userName, *getUserId();
  138. X    char    *path, *absPath();
  139. X
  140. X    begin("take");
  141. X    /* Find the caller's userid. */
  142. X    userName = getUserId();
  143. X    pr1("I am %s\n",userName);
  144. X    pr1("count is %d\n",count);
  145. X
  146. X    for (i=0; i < count; i++) {
  147. X        /* Read the database, and see if we get a match. */
  148. X        if ((path= absPath(arg[i])) == NULL) {
  149. X            PR "%s: could not get the absolute path of \"%s\",",
  150. X                ProgName,arg[i]);
  151. X            PR " is it elsewhere or does it contains a ..?\n");
  152. X            continue;
  153. X        }
  154. X        if (searchDB(userName,path)) {
  155. X            cat(path);
  156. X        }
  157. X    }
  158. X    end();
  159. X}
  160. X
  161. X
  162. X/*
  163. X * give -- put the person and file in the .give database
  164. X */
  165. X void
  166. Xgive(count, arg) int count; char *arg[]; {
  167. X    int    i;
  168. X    char    *absPath();
  169. X    char     *userName;
  170. X    char    *path;
  171. X
  172. X    begin("give");
  173. X    /* Break the user name out of the args vector. */
  174. X    userName = arg[0];
  175. X    count--; 
  176. X    arg = (char **)&arg[1];
  177. X
  178. X    /* Find if the named person has a userid. */
  179. X    if (validateUserId(userName) == 0) {
  180. X        PR "%s: %s is not a known user-id on this system\n",
  181. X            ProgName, userName);
  182. X        exit(BAD);
  183. X    }
  184. X
  185. X    /* And process each of the files in order. */
  186. X    for (i=0; i < count; i++) {
  187. X        /* Find the absolute pathname of the file. */
  188. X        if ((path= absPath(arg[i])) == NULL) {
  189. X            PR "%s: file \"%s\" not found, ignored.\n",
  190. X                ProgName, arg[i]);
  191. X        }
  192. X        else {
  193. X            /* Put them in the database. */
  194. X            addDB(userName,path);
  195. X        }
  196. X    }
  197. X    end();
  198. X}
  199. X
  200. X/*
  201. X * remove -- remove a person-filename pair from the database
  202. X */
  203. X void
  204. Xremove(count, arg) int count; char **arg; {
  205. X    int    i;
  206. X    char    *absPath();
  207. X    char     *userName;
  208. X    char    *path;
  209. X
  210. X    begin("give");
  211. X    /* Break the user name out of the args vector. */
  212. X    userName = arg[0];
  213. X    count--; 
  214. X    arg = (char **)&arg[1];
  215. X
  216. X    /* And remove each of the files in order. */
  217. X    for (i=0; i < count; i++) {
  218. X        /* Find the absolute pathname of the file. */
  219. X        if ((path= absPath(arg[i])) == NULL) {
  220. X            PR "%s: file \"%s\" not found, ignored.\n",
  221. X                ProgName, arg[i]);
  222. X        }
  223. X        else {
  224. X            /* Take them out of the database. */
  225. X            removeDB(userName,path);
  226. X        }
  227. X    }
  228. X    end();
  229. X}
  230. X
  231. X
  232. X/*
  233. X** Filesystem functions
  234. X**
  235. X*/
  236. X
  237. X/* 
  238. X * absPath -- find the absolute pathname of a file, return NULL
  239. X *    if it doesn't have (a canonical and unique) one.
  240. X */
  241. X char *
  242. XabsPath(name) char *name; {
  243. X    static char path[MAXPATHLEN*2];
  244. X    char    *getcwd(), *strcat(), *strcpy();
  245. X
  246. X    begin("abspath");
  247. X    if (*name == '/') {
  248. X        /* Its an absolute path. */
  249. X        (void) strcpy(path,name);
  250. X    }
  251. X    else {
  252. X        /* Its a relative path: prefix the working directory. */
  253. X        if (getcwd(path,MAXPATHLEN) == NULL) {
  254. X            PR "%s: can't find working directory, halting\n",
  255. X                ProgName);
  256. X            exit(AWFULL);
  257. X        }
  258. X        (void) strcat(strcat(path,"/"),name);
  259. X    }
  260. X    if (!canonical(path)) {
  261. X        ret(NULL);
  262. X    }
  263. X    else if (exists(path) == NO) {
  264. X        ret(NULL);
  265. X    }
  266. X    else {
  267. X        ret(path);
  268. X    }
  269. X}
  270. X
  271. X/* 
  272. X * canonical -- test a pathname for a ".." sequence.
  273. X */
  274. X int 
  275. Xcanonical(name) char *name; {
  276. X    char *p, *strchr();
  277. X
  278. X    begin("canonical");
  279. X    p = name;
  280. X    while ((p=strchr(p+1,'.')) != NULL) {
  281. X        if (p[1] == '.') {
  282. X            ret(NO);
  283. X        }
  284. X    }
  285. X    ret(YES);
  286. X}
  287. X
  288. X/*
  289. X * exists -- stat a file for presence/absence
  290. X */
  291. X int
  292. Xexists(path) char *path; {
  293. X        struct stat buf;
  294. X
  295. X    return (stat(path, &buf) != ERR);
  296. X}
  297. X
  298. X
  299. X/*
  300. X** userid functions
  301. X**
  302. X*/
  303. X
  304. X/*
  305. X * getUserId -- Find the user's userid.
  306. X */
  307. X char *
  308. XgetUserId() {
  309. X        struct passwd *p, *getpwuid();
  310. X    unsigned short getuid();
  311. X
  312. X    begin("getUserId");
  313. X    if ((p=getpwuid((int)getuid())) == NULL) {
  314. X        ret(NULL);
  315. X    }
  316. X    else {
  317. X        ret(p->pw_name);
  318. X    }
  319. X}
  320. X
  321. X/*
  322. X * validateUserId -- Find if the named person has a userid. 
  323. X */
  324. X int
  325. XvalidateUserId(name) char *name; {
  326. X    struct passwd *getpwnam();
  327. X
  328. X    return (getpwnam(name) != NULL);
  329. X}
  330. X
  331. X/*
  332. X * ownerIsRunningMe -- return YES if the owner of the program is running it
  333. X */
  334. X int
  335. XownerIsRunningMe() {
  336. X    unsigned short getuid(), geteuid();
  337. X
  338. X    return (getuid() == geteuid());
  339. X}
  340. X
  341. X    
  342. X
  343. X/*
  344. X** database functions -- these happen to use dbm(3x), but anything is
  345. X**    acceptable that can provide the primitives.  Ingres would be 
  346. X**    somewhat nicer...
  347. X*/
  348. X#define MAXNAME 100
  349. X
  350. X/*
  351. X * addDB -- add a person-filename pair.
  352. X */
  353. XaddDB(person,file) char *person, *file; {
  354. X    DATUM    key,
  355. X        content;
  356. X    char    record[MAXNAME+MAXPATHLEN],
  357. X        *strcat(), *strcpy();
  358. X
  359. X    begin("addDB");
  360. X    initDB();
  361. X    key.dptr = strcat(strcat(strcpy(record,person)," "),file);
  362. X    key.dsize = strlen(record)+1;
  363. X    content.dptr = " ";
  364. X    content.dsize = 2;
  365. X    pr1("key is '%s'\n",record);
  366. X    if (store(key,content) < 0) {
  367. X        PR "%s: database failed on a store, halting\n",
  368. X            ProgName);
  369. X        exit(AWFULL);
  370. X    }
  371. X    end();
  372. X}
  373. X
  374. X/*
  375. X * searchDB -- see if a person-filename pair is present.
  376. X */
  377. X int
  378. XsearchDB(person,file) char *person, *file; {
  379. X    DATUM    key, content, fetch();
  380. X    char    record[MAXNAME+MAXPATHLEN],
  381. X        *strcat(), *strcpy();
  382. X
  383. X    begin("searchDB");
  384. X    initDB();
  385. X    key.dptr = strcat(strcat(strcpy(record,person)," "),file);
  386. X    key.dsize = strlen(record)+1;
  387. X    pr1("key is '%s'\n",record);
  388. X    content = fetch(key);
  389. X    pr2("content = '%s' (0x%X)\n",content.dptr,content.dptr);
  390. X    ret(content.dptr != NULL);
  391. X}
  392. X
  393. X/* 
  394. X * removeDB -- remove a person-filename pair
  395. X */
  396. XremoveDB(person,file) char *person, *file; {
  397. X    DATUM    key;
  398. X    char    record[MAXNAME+MAXPATHLEN],
  399. X        *strcat(), *strcpy();
  400. X    int    rc;
  401. X
  402. X    begin("removeDB");
  403. X    initDB();
  404. X    key.dptr = strcat(strcat(strcpy(record,person)," "),file);
  405. X    key.dsize = strlen(record)+1;
  406. X    pr1("key is '%s'\n",record);
  407. X    rc = delete(key);
  408. X    pr1("rc = %d\n",rc);
  409. X    if (rc < 0) {
  410. X        PR "%s: could not remove \"%s\" from database\n",
  411. X            ProgName,record);
  412. X        exit(AWFULL);
  413. X    }
  414. X    end();
  415. X}
  416. X
  417. X/* 
  418. X * printDB -- print all person-filename pairs in the database
  419. X */
  420. XprintDB() {
  421. X    DATUM    key, firstkey(), nextkey();
  422. X
  423. X    begin("printDB");
  424. X    initDB();
  425. X    key = firstkey();
  426. X    if (key.dptr == NULL) {
  427. X        usage();
  428. X    }
  429. X    else {
  430. X        for (; key.dptr != NULL; key=nextkey(key))
  431. X            (void) printf("%s\n",key.dptr);
  432. X    }
  433. X    end();
  434. X}
  435. X
  436. X/*
  437. X * initDB -- open the db file
  438. X */
  439. X static
  440. XinitDB() {
  441. X    static openRqd = YES;
  442. X
  443. X    begin("initDB");
  444. X    if (openRqd) {
  445. X        if (exists(".give.pag") == NO) {
  446. X            (void) creat(".give.dir",0755);
  447. X            (void) creat(".give.pag",0755);
  448. X            /* Success test is the dbminit... */
  449. X        }
  450. X        if (dbminit(".give") < 0) {
  451. X            PR "%s: cannot open .give.[dir|pag] file, halting\n",
  452. X                ProgName);
  453. X            exit(AWFULL);
  454. X        }
  455. X    }
  456. X    openRqd = NO;
  457. X    end();
  458. X}
  459. X
  460. X/*
  461. X * cat -- send a file to stdout.
  462. X */
  463. X#define BLOCKSIZE    1024
  464. Xcat(p) char *p; {
  465. X    char    block[BLOCKSIZE];
  466. X    int    fd, 
  467. X        i;
  468. X
  469. X    begin("cat");
  470. X    pr1("p is '%s'\n",p);
  471. X    if ((fd=open(p,O_RDONLY)) == ERR) {
  472. X        PR "%s: can't open %s (inpossible!)\n",
  473. X            ProgName, p);
  474. X        exit(AWFULL);
  475. X    }
  476. X    while ((i=read(fd,block,(unsigned)BLOCKSIZE)) != 0)
  477. X        (void) write(1,block,(unsigned)i);
  478. X    (void) close(fd);
  479. X}
  480. END_OF_give.c
  481. if test 7990 -ne `wc -c <give.c`; then
  482.     echo shar: \"give.c\" unpacked with wrong size!
  483. fi
  484. # end of overwriting check
  485. fi
  486. if test -f Makefile -a "${1}" != "-c" ; then 
  487.   echo shar: Will not over-write existing file \"Makefile\"
  488. else
  489. echo shar: Extracting \"Makefile\" \(830 characters\)
  490. sed "s/^X//" >Makefile <<'END_OF_Makefile'
  491. X# 
  492. X# give -- half of the v6 give-and-take package
  493. X# 
  494. X# BINDIR is where to put the executable.
  495. X# MANDIR is where the manual pages go, and MANEXT is the extension.
  496. X# for the man pages, e.g., give.1 or give.l or give.m.
  497. X
  498. XBINDIR = /usr/local
  499. XMANDIR = /usr/man/manl
  500. XMANEXT = l
  501. X
  502. X# These should all just be right if the above ones are.
  503. XDIRNAME = $(BINDIR)/give
  504. XDIRNAME_M = $(MANDIR)/give.$(MANEXT)
  505. XLDFLAGS = -ldbm
  506. XCFLAGS = -Y
  507. X
  508. Xgive: give.c
  509. X    $(CC) $(CFLAGS) -o give give.c $(LDFLAGS) 
  510. X
  511. X$(DIRNAME_M): give.1
  512. X    cp give.1 $(DIRNAME_M)
  513. X    chmod 644 $(DIRNAME_M)
  514. X
  515. X$(DIRNAME): give
  516. X    install -c -m 755 give $(DIRNAME)
  517. X
  518. Xinstall: $(DIRNAME_M) # $(DIRNAME)
  519. X
  520. Xuse: 
  521. X    cp $(DIRNAME) ./give
  522. X    chmod 4711 give
  523. X
  524. X
  525. X
  526. Xlint:
  527. X    lint $(CFLAGS) give.c
  528. Xtags:
  529. X    ctags -w give.c
  530. Xgive.shar:
  531. X    shar README give.c Makefile give.1 > give.shar
  532. Xclean:
  533. X    rm -f a.out core *.o give
  534. END_OF_Makefile
  535. if test 830 -ne `wc -c <Makefile`; then
  536.     echo shar: \"Makefile\" unpacked with wrong size!
  537. fi
  538. # end of overwriting check
  539. fi
  540. if test -f give.1 -a "${1}" != "-c" ; then 
  541.   echo shar: Will not over-write existing file \"give.1\"
  542. else
  543. echo shar: Extracting \"give.1\" \(1339 characters\)
  544. sed "s/^X//" >give.1 <<'END_OF_give.1'
  545. X.TH GIVE 1,local
  546. X.SH NAME
  547. Xgive \- a paranoid's copy program
  548. X.SH SYNOPSIS
  549. Xgive [person] file...
  550. X.br
  551. Xgive -d person file...
  552. X
  553. X.SH DESCRIPTION
  554. XGive is a program which will "cat" a particular file to a particular
  555. Xperson, and only that person. When it is called by its owner with a
  556. Xperson's userid and one or more filenames, it remembers the
  557. Xuser-filename pairs. When it called by someone other than the owner
  558. Xwith one or more filenames, it sees if the person is authorized to
  559. Xbe given the file(s), and if so sends a copy to stdout. 
  560. X.PP
  561. XIf the command is given by itself, it will print the current
  562. Xcontents of the .give file(s) and/or a usage message.
  563. X.PP
  564. XIf it is given with the "-d" option, it will delete the person-file
  565. Xpair from the database.
  566. X
  567. X.SH EXAMPLE
  568. Xdave> give drew precious_file
  569. X.sp
  570. Xdrew> cd ~dave 
  571. X.br
  572. Xdrew> give precious_file >$HOME/my_copy
  573. X.br
  574. Xor
  575. X.br
  576. Xdrew> ~dave/give ~dave/precious_file >my_copy
  577. X
  578. X.SH FILES
  579. X ./.give*      the list of people and files.
  580. X
  581. X.SH HISTORY
  582. XThis is a rather old idea, dating from v6's give and take. If we had
  583. XACLs (access control lists), it would also be a useless one.  
  584. X
  585. X.SH BUGS
  586. XThe right copy of "give" has to be executed, which tends to mean you
  587. Xhave to be in the same directory as the files to be given or refer
  588. Xto "give" by an absolute pathname.
  589. X.PP
  590. XIt was written by Dave C-B.  Need I say more?
  591. END_OF_give.1
  592. if test 1339 -ne `wc -c <give.1`; then
  593.     echo shar: \"give.1\" unpacked with wrong size!
  594. fi
  595. # end of overwriting check
  596. fi
  597. echo shar: End of shell archive.
  598. exit 0
  599. -- 
  600.  David Collier-Brown.  |{yunexus,utgpu}!geac!daveb
  601.  Geac Computers Ltd.,  |  Computer science loses its
  602.  350 Steelcase Road,   |  memory, if not its mind,
  603.  Markham, Ontario.     |  every six months.
  604.